package com.thread.waitnotify;

/**
synchronized是和一个锁对象关联的,synchronized限制static方法的时候,
锁对象为这个类的class变量,相当于XXXClass.class.
synchronized限制非static方法的时候,锁对象为这个类的实例(相当于this).

synchronized限制一个对象实例的时候,如(synchronized (xlock)),锁对象为指定的这个对象实例,如xlock.
只有获得锁对象的锁的线程才能执行synchronized限制的代码.
synchronized限制static方法的时候,在某一时刻,同一个虚拟机只能有一个线程正在执行这个static方法,
因为锁对象是这个class的XXXClass.class实例,一个虚拟机只有一个XXXClass.class实例.

synchronized限制某一个类的非static方法的时候,对这个类的某一特定实例,
在某一时刻,同一个虚拟机只能有一个线程正在执行这个方法,但是可以同时执行多个实例的这个特定方法,因为锁对象不同.

wait,notify和notifyAll都只能在一个锁对象上调用,否则会发生如下异常:
java.lang.IllegalMonitorStateException: current thread not owner

void notify()
唤醒在此对象监视器上等待的某一个线程.具体是哪一个可以认为是不确定的.
void notifyAll()
唤醒在此对象监视器上等待的所有线程。
void wait()
导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll()方法.
wait会释放占有的锁,notify和notifyAll不会释放占用的锁.

notifyAll使所有原来在该对象上等待被notify的线程统统退出wait的状态，变成等待该对象上的锁，一旦该对象被解锁，他们就会去竞争。
notify则文明得多，他只是选择一个wait状态线程进行通知，并使它变成等待该对象上的锁，但不惊动其他同样在等待被该对象notify的线程们
 * */

//如果不是在synchronized关联的锁对象调用notify,notifyAll或者wait会有异常.# point 1 有异常发生
//notifyAll会唤醒该锁对象上所有等待的线程.
public class NotifyWaitTest {
	public static Class lock = NotifyWaitTest.class;

    public static void main(String[] args) throws Exception {
    	//TestThread1中的run方法中wait之后的代码是synchronized,唤醒的两个线程是一个执行完成之后,另外一个才能执行.
        new TestThread1().start();
        new TestThread1().start();
        //如果在main方法中启动的是TestThread2,因为在TestThread2的run方法中wait之后的代码不是synchronized的,所以wakeup之后可以并行执行.
        //new TestThread2().start();
        //new TestThread2().start();

        Thread.sleep(3000);
        // NotifyWaitTest.lock.notifyAll(); //# poing 1
        synchronized (NotifyWaitTest.lock) {
            try {
                System.out.println(Thread.currentThread().getName() + " sent notification all");
                NotifyWaitTest.lock.notifyAll();
                Thread.sleep(5000);

                //如果在main方法中改用下面的方式notify,在"sent notification over"之后两个子线程才会从
                //wait暂停的地方继续执行,因为notify并不释放锁,这时候main还占用NotifyWaitTest.lock锁对象的锁.
                //System.out.println(Thread.currentThread().getName() + " sent notification 1");
                //NotifyWaitTest.lock.notify();
                //System.out.println(Thread.currentThread().getName() + " sent notification 2");
                //Thread.sleep(3000);
                //NotifyWaitTest.lock.notify();
                //System.out.println(Thread.currentThread().getName() + " sent notification over");

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

class TestThread1 extends Thread {
    public void run() {
        synchronized (NotifyWaitTest.lock) {
            try {
                System.out.println(Thread.currentThread().getName() + " wait for notification");
                NotifyWaitTest.lock.wait();

                System.out.println(Thread.currentThread().getName() + " wake up");
                for (int i = 0; i < 3; i++) {
                    Thread.sleep(1000);
                    System.out.println(Thread.currentThread().getName() + " doing " + i);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " finished");
        }
    }
}

class TestThread2 extends Thread {

    public void run() {
        synchronized (NotifyWaitTest.lock) {
            System.out.println(Thread.currentThread().getName() + " wait for notification");
            try {
                NotifyWaitTest.lock.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName() + " wake up");
        for (int i = 0; i < 3; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " doing " + i);
        }
    }
}